前一天我們談到了可以從三大法人買賣超,瞭解機構法人在臺股的買賣動向。由於法人資金部位大並且擁有資訊不對稱的優勢,就長期而言,通常法人是市場的贏家,散戶則是市場的輸家,因此我們可以將散戶視為市場的反指標,如果要觀察散戶對股市的看法,可以參考股市的融資融券餘額增減。
在臺灣股票市場,股票交易可以分成「現股交易」和「信用交易」。現股交易就用現金買賣股票;信用交易又分為「融資」和「融券」。用比較白話的說法,融資是向券商借錢買股票;融券是向券商借股票來賣出。投資人必須向券商申請開立信用交易帳戶才能進行信用交易,就交易目的而言,融資是為了做多,而融券則是為了放空。
在臺灣證券市場,法人不能使用融資融券交易,所以融資融券的餘額與增減通常被解讀散戶指標。下圖是 2022 年初至 8 月 31 日止的大盤融資與融券餘額,融資代表看空,融券代表看空,所以融資與融券餘額大多時候是呈現反向關係。
Source:臺灣證券交易所
當融資餘額增加,代表散戶看多,後續股市下跌的機會較大;而融券餘額增加,代表散戶看空,後續股市上漲的機會較大。因為融資餘額增加代表散戶進場,容易造成籌碼不穩定,如果大戶不願意進場幫散戶抬轎,股市就不容易上漲;融券餘額增加代表散戶看壞股市,如果有軋空行情,融券回補就會變成股市上漲的燃料。
融資有擔保維持率,當股票下跌造成整戶擔保維持率不足時,券商就會發出融資追繳通知,必須在期限內完成補錢,如果不補足差額,就會被券商強制賣出,這就是俗稱的「斷頭」。
當大盤出現連續下跌,容易造成融資維持率不足,這時過多的融資就會變成股市加速下跌的助力,因為市場上會有融資的停損賣壓,可能引發融資斷頭潮,形成「融資多殺多」、「散戶人踩人」的狀況。當融資減少時,代表散戶出場,籌碼回歸到法人或大戶手中,短線上,股市就有機會暫時止跌。
有些資訊廠商會提供「大盤融資維持率」的數據。
大盤融資維持率 = 所有融資股票市值 / 大盤融資餘額 =(所有融資股數 x 股票的股價 / 大盤融資餘額
。融資買進股票時的維持率是 166%,當融資維持率低於 130% 時,券商就會發出追繳令,如果當大盤融資維持率逼近 130% 時,則代表市場上的融資散戶幾乎都已經斷頭了,因此大盤融資維持率可以作為一個參考的指標。
下圖是 2022 年初至 8 月 31 日止的大盤融資餘額,可以看出融資餘額與加權指數有正向關係,2022 上半年加權指數一路下跌,市場上的融資餘額也不斷地減少。
Source:臺灣證券交易所
雖然 融資融券餘額 一般被視為散戶指標,但仍須注意的是,市場上也有非屬法人的主力大戶使用融資來放大槓桿加速獲利,因此我們在參考這個指標時,仍需搭配其他數據相互確認。
在證交所網站的 融資融券餘額 頁面,可以按日查詢集中市場的信用交易統計。
證交所首頁 > 交易資訊 > 融資融券與可借券賣出額度 > 融資融券餘額
在「融資融券餘額」頁面,選取「查詢日期」和「分類項目」後按下「查詢」。分類項目選擇「信用交易統計」可查詢大盤統計,選擇「全部」會列出所有上市股票融資融券彙總。
點擊「列印 / HTML」連結,瀏覽器會開新分頁將資訊輸出成可列印的 HTML 頁面。假設資料日期為「民國 111 年 07 月 01 日」,我們會得到以下 URL:
https://www.twse.com.tw/exchangeReport/MI_MARGN?response=html&date=20220701&selectType=MS
以上 URL 可設定的參數如下:
response
:回應資料的格式。指定 html
輸出 HTML 文件;改為 csv
可以另存 CSV 檔案;設定成 json
或不指定則回應 JSON 格式資料。date
:資料日期。接受的日期格式為 yyyyMMdd
,如 20220701
。selectType
:分類項目。MS
為「信用交易統計」;ALL
為「全部」。我們將 URL 查詢參數改為 response=json&dayDate=20220701&selectType=ALL
,證交所就會以 JSON 格式資料回應 2022 年 7 月 1 日的信用交易統計:
{
"stat": "OK",
"creditTitle": "111年07月01日 信用交易統計",
"creditFields": [
"項目",
"買進",
"賣出",
"現金(券)償還",
"前日餘額",
"今日餘額"
],
"creditList": [
[
"融資(交易單位)",
"299,709",
"508,441",
"10,846",
"7,462,957",
"7,243,379"
],
[
"融券(交易單位)",
"76,277",
"88,013",
"1,222",
"509,726",
"520,240"
],
[
"融資金額(仟元)",
"8,576,037",
"17,191,501",
"1,662,750",
"206,723,788",
"196,445,574"
]
],
......
}
在信用交易統計中,通常一個交易單位代表 1000 股,也就是一張。融券是借股票,所以統計的是「交易單位」;融資則區分出「交易單位」和「金額」。由於大盤統計的是市場上所有股票,而不同公司的股票價值是不等的,因此在融資餘額的數據,我們主要會觀察融資金額,而不是融資張數。
開啟 src/scraper/twse-scraper.service.ts
檔案,在 TwseScraperService
加入 fetchMarginTransactions()
方法,並指定 date
參數,表示要取得集中市場集中市場融資融券餘額的日期:
import * as cheerio from 'cheerio';
import * as iconv from 'iconv-lite';
import * as numeral from 'numeral';
import { DateTime } from 'luxon';
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
@Injectable()
export class TwseScraperService {
constructor(private httpService: HttpService) {}
...
async fetchMarginTransactions(date: string) {
// 將 `date` 轉換成 `yyyyMMdd` 格式
const formattedDate = DateTime.fromISO(date).toFormat('yyyyMMdd');
// 建立 URL 查詢參數
const query = new URLSearchParams({
response: 'json', // 指定回應格式為 JSON
date: formattedDate, // 指定資料日期
selectType: 'MS', // 指定分類項目為信用交易統計
});
const url = `https://www.twse.com.tw/en/exchangeReport/MI_MARGN?${query}`;
// 取得回應資料
const responseData = await firstValueFrom(this.httpService.get(url))
.then(response => (response.data.stat === 'OK') ? response.data : null);
// 若該日期非交易日或尚無信用交易統計則回傳 null
if (!responseData) return null;
if (!responseData.creditList.length) return null;
// 整理回應資料
const raw = responseData.creditList
.map(data => data.slice(1)).flat() // 取出買賣金額並減少一層陣列嵌套
.map(data => numeral(data).value() || +data); // 轉為數字格式
const [
marginPurchase, // 融資(交易單位)-買進
marginSale, // 融資(交易單位)-賣出
cashRedemption, // 融資(交易單位)-現金(券)償還
marginBalancePrev, // 融資(交易單位)-前日餘額
marginBalance, // 融資(交易單位)-今日餘額
shortCovering, // 融券(交易單位)-買進
shortSale, // 融券(交易單位)-賣出
stockRedemption, // 融券(交易單位)-現金(券)償還
shortBalancePrev, // 融券(交易單位)-前日餘額
shortBalance, // 融券(交易單位)-今日餘額
marginPurchaseValue, // 融資金額(仟元)-買進
marginSaleValue, // 融資金額(仟元)-賣出
cashRedemptionValue, // 融資金額(仟元)-現金(券)償還
marginBalanceValuePrev, // 融資金額(仟元)-前日餘額
marginBalanceValue, // 融資金額(仟元)-今日餘額
] = raw;
// 計算融資餘額增減(交易單位)
const marginChange = marginBalance - marginBalancePrev;
// 計算融資餘額增減(仟元)
const marginChangeValue = marginBalanceValue - marginBalanceValuePrev;
// 計算融券餘額增減(交易單位)
const shortChange = shortBalance - shortBalancePrev;
return {
date,
marginBalance,
marginBalanceChange,
marginBalanceValue,
marginBalanceValueChange,
shortBalance,
shortBalanceChange,
};
}
}
在 fetchMarginTransactions()
方法中,需要指定 date
參數,表示要取得融資融券餘額的日期。我們定義回傳的物件欄位包含如下:
date
:日期marginBalance
:融資餘額(張)marginBalanceChange
:融資餘額(張)marginBalanceValue
:融資餘額(仟元)marginBalanceValueChange
:融資餘額增減(仟元)shortBalance
:融券餘額增減(張)shortBalanceChange
:融券餘額增減(張)完成後,我們只要呼叫 TwseScraperService
的 fetchMarginTransactions()
方法,就可以按日期取得集中市場融資融券餘額。以日期 2022-07-01
為例:
{
date: '2022-07-01',
marginBalance: 7243379,
marginBalanceChange: -219578,
marginBalanceValue: 196445574,
marginBalanceValueChange: -10278214,
shortBalance: 520240,
shortBalanceChange: 10514
}
在櫃買中心網站的 上櫃股票融資融券餘額 頁面,可以按日查詢上櫃股票融資融券餘額。
櫃買中心首頁 > 上櫃 > 融資融券 > 融資融券餘額表
在「上櫃股票融資融券餘額」頁面選取「資料日期」後,就會列出上櫃股票融資融券餘額統計。
點擊「列印/匯出HTML」連結,瀏覽器會開新分頁將資訊輸出成可列印的 HTML 頁面。假設資料日期為「111/07/01」,我們會得到以下 URL:
https://www.tpex.org.tw/web/stock/margin_trading/margin_balance/margin_bal_result.php?l=zh-tw&o=htm&d=111/07/01&s=0,asc
以上 URL 可設定的參數如下:
l
:輸出資料的語系。zh-tw
為正體中文;en-us
為英文。o
:資料輸出的格式。指定 htm
表示輸出 HTML 文件;改為 csv
可以另存 CSV 檔案;設定成 json
或不指定則回應 JSON 格式資料。d
:資料日期。接受 民國年/月/日
的日期格式。需要注意,若 l
參數指定為 en-us
,則 d
參數需改成 西元年/月/日
的日期格式。s
:指定欄位依照升冪或降冪排序。例如 0,asc
是按代號升冪排序;1,desc
則按名稱降冪排序,依此類推。我們將 URL 查詢參數改為 l=zh-tw&o=json&d=111/07/01
,櫃買中心就會以 JSON 格式資料回應 2022 年 7 月 1 日上櫃股票融資融券餘額:
{
"reportDate": "111/07/01",
"iTotalRecords": 764,
"aaData": [
"00679B",
"元大美債20年",
"588",
"99",
"0",
"0",
"687",
"0",
"0.26",
"256,673",
"0",
"0",
"0",
"0",
"0",
"0",
"0.0",
"256,673",
"0",
"",
...
],
"tfootData_one": [
"1,646,783",
"59,773",
"105,349",
"3,378",
"1,597,829",
"",
"",
"",
"80,440",
"12,314",
"19,566",
"177",
"73,011"
],
"tfootData_two": [
"61,565,604",
"2,331,350",
"5,006,438",
"452,166",
"58,438,350"
]
}
簡化了櫃買中心回傳的 JSON 格式資料,在 aaData
欄位可以得到所有上櫃股票的融資融券餘額。因為我們要查詢的是櫃買市場整體的融資融券餘額統計,所以只需要關注 tfootData_one
與 tfootData_two
欄位的數字即可。
tfootData_one
欄位內的資料依序表示:融資(交易單位)-前日餘額、融資(交易單位)-買進、融資(交易單位)-賣出、融資(交易單位)-現金(券)償還、融資(交易單位)-今日餘額、融券(交易單位)-前日餘額、融券(交易單位)-買進、融券(交易單位)-賣出、融券(交易單位)-現金(券)償還、融券(交易單位)-今日餘額。tfootData_two
欄位內的資料依序表示:融資金額(仟元)-前日餘額、融資金額(仟元)-買進、融資金額(仟元)-賣出、融資金額(仟元)-現金(券)償還、融資金額(仟元)-今日餘額。開啟 src/scraper/tpex-scraper.service.ts
檔案,在 TpexScraperService
加入 fetchMarginTransactions()
方法,並指定 date
參數,表示要取得櫃買市場融資融券餘額的日期:
import * as numeral from 'numeral';
import { DateTime } from 'luxon';
import { Injectable } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom } from 'rxjs';
@Injectable()
export class TpexScraperService {
constructor(private httpService: HttpService) {}
...
async fetchMarginTransactions(date: string) {
// `date` 轉換成 `民國年/MM/dd` 格式
const dt = DateTime.fromISO(date);
const year = dt.get('year') - 1911;
const formattedDate = `${year}/${dt.toFormat('MM/dd')}`;
// 建立 URL 查詢參數
const query = new URLSearchParams({
l: 'zh-tw', // 指定語系為正體中文
d: formattedDate, // 指定日期
o: 'json', // 指定回應格式為 JSON
});
const url = `https://www.tpex.org.tw/web/stock/margin_trading/margin_balance/margin_bal_result.php?${query}`;
// 取得回應資料
const responseData = await firstValueFrom(this.httpService.get(url))
.then(response => (response.data.iTotalRecords > 0) && response.data);
// 若該日期非交易日或尚無成交資訊則回傳 null
if (!responseData) return null;
// 整理回應資料
const raw = [
...responseData.tfootData_one,
...responseData.tfootData_two
] // 取出融資融券統計
.map(data => numeral(data).value()) // 轉為數字格式
.filter(data => data); // 移除 null 值
const [
marginBalancePrev, // 融資(交易單位)-前日餘額
marginPurchase, // 融資(交易單位)-買進
marginSale, // 融資(交易單位)-賣出
cashRedemption, // 融資(交易單位)-現金(券)償還
marginBalance, // 融資(交易單位)-今日餘額
shortBalancePrev, // 融券(交易單位)-前日餘額
shortCovering, // 融券(交易單位)-買進
shortSale, // 融券(交易單位)-賣出
stockRedemption, // 融券(交易單位)-現金(券)償還
shortBalance, // 融券(交易單位)-今日餘額
marginBalanceValuePrev, // 融資金額(仟元)-前日餘額
marginPurchaseValue, // 融資金額(仟元)-買進
marginSaleValue, // 融資金額(仟元)-賣出
cashRedemptionValue, // 融資金額(仟元)-現金(券)償還
marginBalanceValue, // 融資金額(仟元)-今日餘額
] = raw;
// 計算融資餘額增減(交易單位)
const marginBalanceChange = marginBalance - marginBalancePrev;
// 計算融資餘額增減(仟元)
const marginBalanceValueChange = marginBalanceValue - marginBalanceValuePrev;
// 計算融券餘額增減(交易單位)
const shortBalanceChange = shortBalance - shortBalancePrev;
return {
date,
marginBalance,
marginBalanceChange,
marginBalanceValue,
marginBalanceValueChange,
shortBalance,
shortBalanceChange,
};
}
}
在 fetchMarginTransactions()
方法中,需要指定 date
參數,表示要取得融資融券餘額的日期。我們定義回傳的物件欄位包含如下:
date
:日期marginBalance
:融資餘額(張)marginBalanceChange
:融資餘額(張)marginBalanceValue
:融資餘額(仟元)marginBalanceValueChange
:融資餘額增減(仟元)shortBalance
:融券餘額增減(張)shortBalanceChange
:融券餘額增減(張)完成後,我們只要呼叫 TpexScraperService
的 fetchMarginTransactions()
方法,就可以按日期櫃買市場融資融券餘額。以日期 2022-07-01
為例:
{
date: '2022-07-01',
marginBalance: 1597829,
marginBalanceChange: -48954,
marginBalanceValue: 58438350,
marginBalanceValueChange: -3127254,
shortBalance: 73011,
shortBalanceChange: -7429
}
本系列文已正式出版為《Node.js 量化投資全攻略:從資料收集到自動化交易系統建構實戰》。本書新增了全新內容和實用範例,為你提供更深入的學習體驗!歡迎參考選購,開始你的量化投資之旅!
天瓏網路書店連結:https://www.tenlong.com.tw/products/9786263336070